/*
 */
package aptech.eproject.logictics.dao.kien;

import aptech.eproject.logictics.db.Delivery;
import aptech.eproject.logictics.db.Package;
import aptech.eproject.logictics.db.Route;
import aptech.eproject.logictics.db.TripPackage;
import aptech.eproject.logictics.db.TripRoute;
import aptech.eproject.logictics.db.TripRouteStatus;
import aptech.eproject.logictics.db.Warehouse;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Kien Nguyen <solidfoxrock at gmail.com>
 */
@Stateless
public class DeliveryService implements DeliveryServiceRemote {

    @PersistenceContext
    private EntityManager em;

    /**
     * Find a {@code Delivery} instance by a unique tracking code
     * @param code Tracking code
     * @return {@code Delivery} instance
     */
    @Override
    public Delivery findDeliveryByTrackingCode(String code) {
        Query q = em.createNamedQuery("findDeliveryByTrackingCode");
        q.setParameter(1, code);
        Delivery d;
        try {
            d = (Delivery) q.getSingleResult();
        } catch (NoResultException e) {
            d = null;
        }
        return d;
    }

    /**
     * Find current location of a package
     * @param p Package
     * @return
     * <li> null if package status is <em>Planned</em>
     * <li> name of start Branch if package status is <em>Waiting</em>
     * <li> name of destination Branch if package status is <em>Delivering</em>
     * <li> consignee address if package status is <em>Finished</em>
     * <li> name of the current Branch if package status is <em>Consigning</em>
     */
    @Override
    public String findLocation(Package p) {
        String msg = null;
        int id = p.getPackageId();
        Delivery d;
        switch (p.getDeliveryStatus()) {
            case Planned:
                break;
            case Delivering:
                d = p.getDelivery();
                msg = d.getDestinationBranch().getBranchName();
                break;
            case Finished:
                d = p.getDelivery();
                msg = d.getConsigneeAddress();
                break;
            case Waiting:
            case Consigning:
                Query q1 = em.createQuery(
                        "SELECT w FROM Warehouse w WHERE w.package.packageId = ?1 "
                        + "AND w.isRemoved = false");
                q1.setParameter(1, id);
                try {
                    Warehouse w = (Warehouse) q1.getSingleResult();
                    // no exception means there is a single result
                    msg = w.getBranch().getBranchName();
                } catch (NonUniqueResultException e) {
                    throw new NonUniqueResultException(
                            "Found more than one Warehouse instance where packageId = "
                            + id + " and isRemoved = false. "
                            + "This should never happens.");
                } catch (NoResultException e) {
                    // exception means all instances have isRemoved = true
                    Query q2 = em.createQuery(
                            "SELECT tp FROM TripPackage tp WHERE tp.package.packageId = ?1 "
                            + "AND tp.isUnloaded = false");
                    q2.setParameter(1, id);
                    try {
                        TripPackage tp = (TripPackage) q2.getSingleResult();

                        // no exception means there is a single result
                        int tripId = tp.getTrip().getTripId();
                        Query q3 = em.createQuery(
                                "SELECT tr FROM TripRoute tr WHERE tr.trip.tripId = ?1 "
                                + "AND tr.status = ?2");
                        q3.setParameter(1, tripId);
                        q3.setParameter(2, TripRouteStatus.Coming);
                        try {
                            TripRoute tr = (TripRoute) q3.getSingleResult();

                            // no exception means there is a single result
                            Route route = tr.getRoute();
                            msg = route.getFromBranch().getBranchName();
                        } catch (NonUniqueResultException ex) {
                            throw new NonUniqueResultException(
                                    "Found more than one TripRoute instance where tripId = "
                                    + tripId + " and status = Coming. "
                                    + "This should never happens.");
                        }
                    } catch (NonUniqueResultException ex) {
                        throw new NonUniqueResultException(
                                "Found more than one TripPackage instance where packageId = "
                                + id + " and isUnloaded = false. "
                                + "This should never happens.");
                    }
                }
                break;
            default:
                throw new IllegalStateException(""
                        + "Invalid status of package with id " + id
                        + ". This should never happens");
        }
        return msg;
    }
}
